home *** CD-ROM | disk | FTP | other *** search
- /**************************************
- cDotsPane.c
-
- SUPERCLASS = CPanorama
-
- Methods for the dots pane. The dots pane contains the grid where the
- game is actually played. Line segments are selected by clicking on the area
- between two horizontal or two vertical dots. When the four line segments
- surrounding a grid cell are selected, the pattern associated with the
- player completing the 'box' is placed inside the cell.
-
- ****************************************/
-
- #include <CScrollPane.h>
- #include "cDotsDoc.h"
- #include "cDotsPane.h"
- #include "cDotsTask.h"
- #include "dotsTypes.h"
-
- /*** Class Constants ***/
- #define kHalfDotSize 3
- #define kFullDotSize (2*kHalfDotSize+1)
- #define kHalfLineSize 1
- #define kFullLineSize (2*kHalfLineSize+1)
- #define kLineOffset ((kFullDotSize - kFullLineSize) / 2)
- #define kDotSpacing (4*kFullDotSize)
- #define UNDOMoveIndex 1 /* String index for undo */
-
- /*** Globals ***/
- extern Pattern *dgPlayerPats;
-
- /******* C O N S T R U C T I O N *******/
-
- /*** IDotsPane {OVERRIDE}
- *
- * Initialize instance variables
- */
- void cDotsPane::IDotsPane(CView *anEnclosure, CBureaucrat *aSupervisor,
- short aWidth, short aHeight,
- short aHEncl, short aVEncl,
- SizingOption aHSizing, SizingOption aVSizing)
- {
- /* Call the inherited method */
- IPanorama(anEnclosure, aSupervisor, aWidth, aHeight,
- aHEncl, aVEncl, aHSizing, aVSizing);
- /* Set horiz and vert scales so that scrolling is by dot spacing
- ** rather than 1 pixel at a time */
- SetScales(kDotSpacing, kDotSpacing);
- SetWantsClicks(true); /* Lines are selected by mouse clicks */
- }
-
- /******** D R A W I N G **********/
-
- /*** Draw {OVERRIDE}
- *
- * The area parameter gives the portion of the
- * pane that needs to be redrawn. Area is in frame coordinates.
- */
- void cDotsPane::Draw(Rect *area)
- {
- int row, col;
-
- /* Draw entire matrix. Could be more selective and
- ** base draw on input area */
- for (row = 0; row <= kMaxRow; row++)
- for (col = 0; col <= kMaxCol; col++)
- drawCorner(row, col);
- }
-
-
- /*** drawCorner
- *
- * Draws the grid dots, grid lines and fills in player boxes
- */
- void cDotsPane::drawCorner(int row, int col)
- {
- Rect r;
- tBoxState boxState;
-
- if ((row < kMaxRow) && (col < kMaxCol)) {
- PenNormal();
- box2Rect(row, col, &r); /* Get box rectangle */
-
- /* first draw the box if it needs to be shaded in */
- boxState = ((cDotsDoc *)itsSupervisor)->getBoxState(row, col);
- if (boxState == kBoxPlayer1) {
- FillRect(&r, &dgPlayerPats[kPlayer1]);
- FrameRect(&r);
- }
- else if (boxState == kBoxPlayer2) {
- FillRect(&r, &dgPlayerPats[kPlayer2]);
- FrameRect(&r);
- }
- }
-
- dot2Rect(row, col, &r); /* Get dot rectangle */
-
- PenNormal();
- PenSize(kFullLineSize, kFullLineSize);
-
- /* Draw the line down from the dot (if any) */
- if ((row < kMaxRow) &&
- (((cDotsDoc *)itsSupervisor)->getLineState(vLine, row, col))) {
- MoveTo(r.left+kLineOffset, r.top+kLineOffset);
- Line(0, kDotSpacing);
- }
-
- /* Draw the line right from the dot (if any) */
- if ((col < kMaxCol) &&
- (((cDotsDoc *)itsSupervisor)->getLineState(hLine, row, col))) {
- MoveTo(r.left+kLineOffset, r.top+kLineOffset);
- Line(kDotSpacing, 0);
- }
-
- FillOval(&r, black); /* Draw the dot */
- }
-
-
- /*** box2Rect
- *
- * Returns the rectangle defining the box
- */
- void cDotsPane::box2Rect(int row, int col, Rect *r)
- {
- Point center;
-
- dotCenter(row, col, ¢er);
- SetRect(r, 0, 0, kDotSpacing+1, kDotSpacing+1);
- OffsetRect(r, center.h, center.v);
- InsetRect(r, kHalfLineSize+4, kHalfLineSize+4);
- }
-
-
- /*** dot2Rect
- *
- * Returns the rectangle defining a dot
- */
- void cDotsPane::dot2Rect(int row, int col, Rect *r)
- {
- Point center;
-
- dotCenter(row, col, ¢er);
- SetRect(r, -kHalfDotSize, -kHalfDotSize, kHalfDotSize+1, kHalfDotSize+1);
- OffsetRect(r, center.h, center.v);
- }
-
-
- /*** dotCenter
- *
- * Returns center coord of a given dot
- */
- void cDotsPane::dotCenter(int row, int col, Point *center)
- {
- SetPt(center, kDotSpacing*(col+1), kDotSpacing*(row+1));
- }
-
- /*** line2Pt
- *
- * Converts coord of line to a pt on grid
- */
- void cDotsPane::line2Pt(tLineDir direction, int row, int col, Point *pt)
- {
- /* Set pt to center of dot */
- dotCenter(row, col, pt);
- /* Offset it to be on the requested line */
- if (direction == hLine)
- pt->h = pt->h + kHalfDotSize + 1;
- else
- pt->v = pt->v + kHalfDotSize + 1;
- }
-
-
- /*** line2Rect
- *
- * Convert coordinates of a line to a rectangle. Used for highlighting
- * while tracking and for invalidating when line is chosen
- */
- void cDotsPane::line2Rect(tLineDir direction, int row, int col, Rect *r)
- {
- Point center;
-
- /* Set pt to center of dot */
- dotCenter(row, col, ¢er);
- /* Offset it to be on the requested line */
- if (direction == hLine)
- SetRect(r, 0, -kHalfLineSize, kDotSpacing+1, kHalfLineSize+1);
- else
- SetRect(r, -kHalfLineSize, 0, kHalfLineSize+1, kDotSpacing+1);
- OffsetRect(r, center.h, center.v);
- }
-
-
- /*** pt2Line
- *
- * Convert point in grid to the coordinates of a line
- */
- Boolean cDotsPane::pt2Line(Point pt, tLineDir *direction, int *row, int *col)
- {
- Boolean ok;
- int modH;
- int modV;
-
- ok = FALSE;
-
- /* Offset pt by slop allowed before line */
- pt.h = pt.h + kFullDotSize;
- pt.v = pt.v + kFullDotSize;
-
- /* Determine values of row and col */
- *row = pt.v / kDotSpacing - 1;
- *col = pt.h / kDotSpacing - 1;
-
- /* Check to see if point selected is on the grid */
- ok = (*row >= 0) && (*row <= kMaxRow) &&
- (*col >= 0) && (*col <= kMaxCol);
- if (ok) {
- /* Consider taking pt.v % kDotSpacing. In order to
- ** be on a horizontal line, this must be in the
- ** range 0..2*kFullDotSize */
- modH = pt.h % kDotSpacing;
- modV = pt.v % kDotSpacing;
-
- /* Pick the closest line to the point */
- if (modH < modV) {
- *direction = vLine;
- ok = (*row < kMaxRow) && (modH <= 2*kFullDotSize);
- } else {
- *direction = hLine;
- ok = (*col < kMaxCol) && (modV <= 2*kFullDotSize);
- }
- }
- if (!ok)
- *row = *col = -1;
- return(ok);
- }
-
-
- /*** invalLine
- *
- * Invalidate line so that it will redraw on update
- */
- void cDotsPane::invalLine(tLineDir direction, int row, int col)
- {
- Rect r;
-
- line2Rect(direction, row, col, &r); /* Get line's rectangle */
-
- /* Set to dots pane's port before invalidation
- ** otherwise may be drawing in a different port */
- Prepare();
- InvalRect(&r);
- }
-
-
- /*** invalBox
- *
- * Invalidate box so that it will redraw on update
- */
- void cDotsPane::invalBox(int row, int col)
- {
- Rect r;
-
- box2Rect(row, col, &r); /* Get box's rectangle */
-
- /* Set to dots pane's port before invalidation
- ** otherwise may be drawing in a different port */
- Prepare();
- InvalRect(&r);
- }
-
- /******** M O U S E T R A C K I N G *********/
-
- /*** DoClick {OVERRIDE}
- *
- * Respond to a mouse down in the dots pane
- */
- void cDotsPane::DoClick(Point hitPt, short modifierKeys, long when)
- {
- Rect bounds;
- cDotsTask *theDotsTask;
- short theHScale;
- short theVScale;
-
- /* Set up a task both for tracking the mouse and for do/undo */
- theDotsTask = new(cDotsTask);
- theDotsTask->IDotsTask(UNDOMoveIndex, this, (cDotsDoc *)itsSupervisor);
-
- /* Set up a pin rect for autoScroll based on panorama bounds */
- GetScales(&theHScale, &theVScale);
- GetBounds(&bounds);
- bounds.top *= theVScale;
- bounds.left *= theHScale;
- bounds.bottom *= theVScale;
- bounds.right *= theHScale;
-
- TrackMouse(theDotsTask, hitPt, &bounds);
-
- /* Only save for undo if a valid move was made */
- if (theDotsTask->validMove())
- itsSupervisor->Notify(theDotsTask); /* Let doc save for undo */
- else
- theDotsTask->Dispose();
- }